package com.block.datapush.service.apipush.utils;

import cn.hutool.core.codec.Base64;
import com.google.common.collect.Maps;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import java.security.*;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Map;


public class WangXunRsaUtils {

    private static final String RSA = "RSA";

    public static final String SIGN_ALGORITHMS = "SHA1WithRSA";
    /**

     @Fields KEY_SIZE : 密钥长度 于原文长度对应 以及越长速度越慢
     */
    public static final int KEY_SIZE = 1024;
    /**

     @Fields keyMap : 随机产生的公钥与私钥 0-公钥 1-私钥
     /
     public static Map<Integer, String> keyMap = new HashMap<Integer, String>();
     /*
     @Title: GeneratorKey
     @Description: 随机生成密钥对
     @param
     @return Map<Integer, String> keyMap 秘钥对 0-公钥 1-私钥
     @throws Exception
     */
    public static Map<String,String> generatorKey() {
        KeyPairGenerator keyPairGen = null;
        try {
            keyPairGen = KeyPairGenerator.getInstance(RSA);
        } catch (NoSuchAlgorithmException e) {
            throw new RuntimeException("生成ras密钥对异常");
        }
        keyPairGen.initialize(KEY_SIZE, new SecureRandom());
        KeyPair keyPair = keyPairGen.generateKeyPair();
// 生成秘钥对
        RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate(); // 得到私钥
        RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic(); // 得到公钥
// base64转码
        String publicKeyString = Base64.encode(publicKey.getEncoded());
        String privateKeyString =Base64.encode((privateKey.getEncoded()));
        Map<String, String> param = Maps.newHashMap();
        param.put("publicKey",publicKeyString);
        param.put("privateKey",privateKeyString);
        return param;
    }
    /**

     @Title: encrypt
     @Description: RSA公钥加密
     @param encryptData 待加密数据
     @param publicKey Base64Util编码的公钥
     @return String 加密后的数据
     @throws
     */
    public static String encrypt(String encryptData, String publicKey) throws Exception {
        try {
// Base64Util编码的公钥，需要先decode
            byte[] decoded = Base64.decode(publicKey.getBytes("UTF-8"));
            RSAPublicKey pubKey = (RSAPublicKey) KeyFactory.getInstance(RSA)
                    .generatePublic(new X509EncodedKeySpec(decoded));
// RSA加密
            Cipher cipher = Cipher.getInstance(RSA);
            cipher.init(Cipher.ENCRYPT_MODE, pubKey);
            String outStr = Base64.encode(cipher.doFinal(encryptData.getBytes("UTF-8")));
            return outStr;
        } catch (NoSuchAlgorithmException e) {
            throw new NoSuchAlgorithmException("无此加密算法，请检查环境");
        } catch (NoSuchPaddingException e) {
            throw new NoSuchPaddingException("明文数据未找到");
        } catch (InvalidKeyException e) {
            throw new InvalidKeyException("加密秘钥非法，请检查");
        } catch (IllegalBlockSizeException e) {
            throw new IllegalBlockSizeException("明文长度非法");
        } catch (BadPaddingException e) {
            throw new BadPaddingException("明文数据已损坏");
        } catch (Exception e) {
            e.printStackTrace();
            throw new Exception("其他错误:", e);
        }
    }
    /**

     @Title: decrypt
     @Description: RSA私钥解密
     @param privateKey Base64Util编码的私钥
     @return String
     @throws Exception 解密过程中的异常信息
     */
    public static String decrypt(String decryptData, String privateKey) {
        try {
// 64位解码 加密后的字符串
            byte[] inputByte = Base64.decode(decryptData.getBytes("UTF-8"));
            byte[] decoded = Base64.decode(privateKey.getBytes("UTF-8"));
            RSAPrivateKey priKey = (RSAPrivateKey) KeyFactory.getInstance(RSA)
                    .generatePrivate(new PKCS8EncodedKeySpec(decoded));
            Cipher cipher = Cipher.getInstance(RSA);
            cipher.init(Cipher.DECRYPT_MODE, priKey);
            return new String(cipher.doFinal(inputByte));
        }catch (Exception e){
            throw new RuntimeException("RSA 解密失败");
        }
    }
    /**

     @param content 待签名数据
     @param privateKey 私钥字符串
     @return String 签名域
     @throws
     @Title: sign
     @Description: RSA签名
     */
    public static String sign(String content, String privateKey) throws Exception {
        PKCS8EncodedKeySpec priPKCS8 = new PKCS8EncodedKeySpec(Base64.decode(privateKey.getBytes("UTF-8")));
        KeyFactory keyf = KeyFactory.getInstance(RSA);
        PrivateKey priKey = keyf.generatePrivate(priPKCS8);
        Signature signature = Signature.getInstance(SIGN_ALGORITHMS);
        signature.initSign(priKey);
        signature.update(content.getBytes());
        byte[] signed = signature.sign();
        return java.util.Base64.getEncoder().encodeToString(signed);
    }
    /**

     @Title: verify
     @Description: RSA验签名检查
     @param content 待签名数据
     @param sign 签名域
     @param publicKey Base64Util后的公钥字符串
     @return boolean 验签结果
     @throws
     */
    public static boolean verify(String content, String sign, String publicKey) {
        try {
            KeyFactory keyFactory = KeyFactory.getInstance(RSA);
            byte[] encodedKey = Base64.decode(publicKey.getBytes("UTF-8"));
            if (encodedKey == null) {
                return false;
            }
            PublicKey pubKey = keyFactory.generatePublic(new X509EncodedKeySpec(encodedKey));
// 用私钥对信息生成数字签名
            Signature signature = Signature.getInstance(SIGN_ALGORITHMS);
            signature.initVerify(pubKey);
            signature.update(content.getBytes());
// 验证方法 返回true则为比对成功
            return signature.verify(Base64.decode(sign.getBytes("UTF-8")));
        }catch (Exception e){
            return false;
        }
    }
    public static void main(String[] args) {
        Map<String,String> map = generatorKey();
        System.out.println(map.get("publicKey"));
        System.out.println(map.get("privateKey"));
    }
}
